package com.tbit.uqbike.client.handler.borrowbikehandler;

import com.tbit.common.utils.TraceUtil;
import com.tbit.uqbike.center.pojo.MachineStatus;
import com.tbit.uqbike.client.common.ResultMsg;
import com.tbit.uqbike.client.constant.*;
import com.tbit.uqbike.client.dao.core.AccountConfigExtDao;
import com.tbit.uqbike.client.dao.core.AppointMentDao;
import com.tbit.uqbike.client.dao.core.BorrowCheckConfigLogDao;
import com.tbit.uqbike.client.dao.core.MachineOccupyDao;
import com.tbit.uqbike.client.filter.servlet.TraceFilter;
import com.tbit.uqbike.client.pojo.*;
import com.tbit.uqbike.client.pojo.borrowbike.BorrowCheckConfigLog;
import com.tbit.uqbike.client.pojo.newEntity.AccountConfigExt;
import com.tbit.uqbike.client.service.*;
import com.tbit.uqbike.client.util.DateTimeUtil;
import com.tbit.uqbike.client.vo.borrow.BorrowBikeVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.UUID;

/**
 * @author lh2
 * @ClassName: MachineStatusCheckHandler
 * @Description: 车辆状态检测处理器，检测车辆低电，故障，头盔丢失等状态
 * @date 2023-07-27 11:40:50
 */
@Slf4j
@Component
public class MachineStatusCheckHandler extends AbstractCheckHandler {
    @Autowired
    private AccountService accountService;
    @Autowired
    private MachineStatusService machineStatusService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private TerControlService terControlService;
    @Autowired
    private MachineFaultService machineFaultService;
    @Autowired
    private UserService userService;
    @Autowired
    private MachineBorrowService machineBorrowService;
    @Autowired
    private ParkService parkService;
    @Autowired
    private AppointMentDao appointMentDao;
    @Autowired
    private MachineOccupyDao machineOccupyDao;
    @Autowired
    private BorrowCheckConfigLogDao borrowCheckConfigLogMapper;
    @Autowired
    private AccountConfigExtDao accountConfigExtDao;

    @Override
    public ResultMsg handle(BorrowBikeVO vo, String serialNO) {
        log.info("【车辆状态检测处理器】校验开始...");
        // 降级：如果配置了降级，则跳过此处理器，执行下一个处理器
        if (super.getConfig().getDown() == 1) {
            log.info("【车辆状态检测处理器】被降级，已自动跳过！");
            return super.next(vo, serialNO);
        }

        User user = vo.getUser();
        User userdb = userService.getByUserId(user.getUserId());
        Machine machine = vo.getMachine();
        AccountConfig accountConfig = vo.getAccountConfig();
        // 判断设备是否在品牌下面
        Account accountAgent = accountService.getByAdAccountId(machine.getAccountId());
        if (!userdb.getAccountId().equals(accountAgent.getParentId())) {
            return ResultMsg.fail(-30005, "该编号不存在", TraceUtil.getTraceIdByLocal());
        }
        if (machine.getState().equals(MachineStateConstant.MACHINE_STATE_GZ)) {
            return ResultMsg.fail(-3029, "该车存在故障，请更换车辆", TraceUtil.getTraceIdByLocal());
        }
        if (machine.getState().equals(MachineStateConstant.MACHINE_STATE_DTF)) {
            return ResultMsg.fail(-3012, "车辆未投放，请更换车辆",TraceUtil.getTraceIdByLocal());
        }
        if (!machine.getState().equals(MachineStateConstant.MACHINE_STATE_ZCYY)) {
            return ResultMsg.fail(-3063, "不可租借车辆，请更换一辆车",TraceUtil.getTraceIdByLocal());
        }
        // 判断是否有借出未还的车辆
        MachineBorrow machineBorrowUser = machineBorrowService.getByUserId(user.getUserId());
        if (machineBorrowUser != null) {
            return ResultMsg.fail(-3005, "存在未还的车辆，请先还车后再借车",TraceUtil.getTraceIdByLocal());
        }
        // 判断是否是运维占用
        MachineOccupy machineOccupy = machineOccupyDao.getByMachineId(machine.getMachineId());
        if (machineOccupy != null) {
            return ResultMsg.fail(-3001, "该车正在骑行",TraceUtil.getTraceIdByLocal());
        }
        // 缓存是否存在借车信息,存在去数据库看下是否有重复数据
        String borrows = redisService.get(RedisConstant.MACHINE_RIDELOG + machine.getMachineId());
        if (borrows != null) {
            MachineBorrow machineBorrow = machineBorrowService.getByMachineId(machine.getMachineId());
            if (machineBorrow != null) {
                return ResultMsg.fail(-3001, "该车正在被骑行",TraceUtil.getTraceIdByLocal());
            } else {
                redisService.del(RedisConstant.MACHINE_RIDELOG + machine.getMachineId());
                redisService.del(RedisConstant.USER_RIDELOG + user.getUserId());
            }
        } else {
            MachineBorrow machineBorrow = machineBorrowService.getByMachineId(machine.getMachineId());
            if (machineBorrow != null) {
                return ResultMsg.fail(-3001, "该车正在被骑行",TraceUtil.getTraceIdByLocal());
            }
        }
        // 判断设备是否被预约
        if (accountConfig != null && accountConfig.getAppoint() == 1) {
            AppointMent appointMent = appointMentDao.getByMachineId(machine.getMachineId());
            if (appointMent != null) {
                /** 判断预约是否达到预约时长 */
                if (DateTimeUtil.getTimeDF(
                        DateTimeUtil.getLastTime(DateTimeUtil.DateTimeToString(appointMent.getAppointmentTime()),
                                accountConfig.getAppointTime() * 60),
                        DateTimeUtil.getNowTime()) >= 0) {
                    appointMentDao.del(appointMent.getUserId());
                } else {
                    /** 非本人扫码，不能借车 */
                    if (!appointMent.getUserId().equals(userdb.getUserId())) {
                        return ResultMsg.fail(-160004, "该车辆已被预约，请换一台车",TraceUtil.getTraceIdByLocal());
                    }
                }
            }
        }
        // 查询车辆是否存在遗留停车记录
        Park park = parkService.getByMachineId(machine.getMachineId());
        if (park != null) {
            parkService.delByMachineId(machine.getMachineId());
        }
        // 兼容用户上报故障车辆是否可再次借出
        if ((accountConfig != null && accountConfig.getUserFaultLimit() == 1)) {
            MachineFault machineFault = machineFaultService.getByMachineId(machine.getMachineId());
            if (machineFault != null && machineFault.getFrom() == 1) {
                return ResultMsg.fail(-3028, "车辆故障，请更换车辆骑行",TraceUtil.getTraceIdByLocal());
            }
        }
        if (this.userFeedbackLimit(machine.getAccountId())) {
            MachineFault machineFault = machineFaultService.getByMachineId(machine.getMachineId());
            if (machineFault != null && machineFault.getFrom() == 3) {
                return ResultMsg.fail(-3028, "车辆故障，请更换车辆骑行",TraceUtil.getTraceIdByLocal());
            }
        }
        MachineStatus machineStatus = machineStatusService.getByMachineNO(machine.getMachineNO(),
                MapConstant.MAP_GOOGLE);
        /** 电量判断,只判断电单车 */
        if (machineStatus != null && machine.getMachineType().equals(MachineStateConstant.MACHINE_TYPE_ELECT_BIKE)) {
            /** 电量是否足够 */
            if (machineStatus.getSocPercent() <= accountConfig.getBorrowSocLimit()) {
                /** 发送电量不足语音指令 */
                String serNO = UUID.randomUUID().toString();
                terControlService.sendControl(serNO, machine.getMachineNO(), ControlTypeConstant.CONTROL_TYPE_VOICE,
                        ControlTypeConstant.CONTROL_TYPE_VOICE_LOWPOWER, "", machine, true, null, null, null);
                return ResultMsg.fail(-3031, "电量过低，请更换一辆车",TraceUtil.getTraceIdByLocal());
            }
        }

        log.info("【车辆状态检测处理器】校验通过！");
        BorrowCheckConfigLog bccLog = borrowCheckConfigLogMapper.findByNameAndSerialNO(
                this.getConfig().getHandlerName(), serialNO);
        if (bccLog != null) {
            bccLog.setExecuteResult(1);
            borrowCheckConfigLogMapper.updateByPrimaryKeySelective(bccLog);
        }
        // 执行下一个处理器
        return super.next(vo, serialNO);
    }

    /**
     * @description: 根据平台id判断是否开启了意见反馈的借车限制开关
     * @author: mo.shanyong
     * @date: 2024/11/20 10:25
     * @param: accountId 所在的平台id
     * @return: boolean
     */
    public boolean userFeedbackLimit(Integer accountId){
        AccountConfigExt configExt = accountConfigExtDao.selectByAccountIdAndKey(accountId, AccountConfigExtConstant.USER_FEEDBACK_LIMIT);
        return Objects.nonNull(configExt) && Integer.valueOf(configExt.getParamValue()) == 1;
    }
}
